-
-
Notifications
You must be signed in to change notification settings - Fork 183
uefi: Refactor PciRootBridgeIo::enumerate() with tree-topology information #1830
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
2a46de0 to
fbed494
Compare
phip1611
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working on this! My main concern is my lack of domain knowledge of PCIe. Please elaborate a little more to help me understand what's going on :)
| // test is more interesting. | ||
| cmd.args([ | ||
| "-device", | ||
| "ioh3420,id=root_port1,bus=pcie.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not that familiar with PCI. Could you please elaborate a little?
- why adding a root port? Is this equivalent to adding a new PCI bus?
- what is
x3130-upstreamand why are you using it here? - what is
x3130-downstreamand why are you using it here? virtio-scsi-pciis just a random PCI device without serving a functionality here except for appearing on the PCIe bus?- why are you specifying
chassis=9|10?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Much of this is qemu specific syntax:
ioh3420 reserves a port in pcie.0 - the pcie root port, also called pcie root complex. I imagine this like soldering a PCIe socket on your mainboard, where you can plug stuff in.
Into this socket, we then plug a x3130-upstream. That's a PCIe switch.
x3130-downstream is the other side of the swich, where you can plug child devices in.
I have no idea what chassis is, the way I understood it, it can be any number as long as they are unique. All bridges/switches have this obligatory parameter.
The scsi devices are just for testing, like you said.
Difference PCIe switches and PCIe bridges:
Both allocate a new subordinate bus. Both allow connecting devices to them, which they "pass through" to the port where they are connected upstream. The key difference is, that for you to pass 2 lanes through a bridge, it needs to be connected with 2 lanes to its upstream. Whereas PCIe switches can do switching. They can tunnel y downstream lanes through x upstream lanes - sacrificing speed if y > x (like with network switches). They are rather seldom, which is why I wanted to test it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| "PCI Device: [{bus}, {dev}, {fun}]: vendor={vendor_id:04X}, device={device_id:04X}, class={class_code:02X}, subclass={subclass_code:02X}" | ||
| "PCI Device: [{bus:02x}, {dev:02x}, {fun:02x}]: vendor={vendor_id:04X}, device={device_id:04X}, class={class_code:02X}, subclass={subclass_code:02X}" | ||
| ); | ||
| for child_bus in pci_tree.iter_subsequent_busses_for(addr) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instead of just iterating, would it make sense to explictely check for the expected PCIe devices?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The bus numbers are dynamically allocated and thus might vary.
But I've done something like you suggest in the follow-up MR here, based on device paths: 582714a
fbed494 to
602c776
Compare
…ation - Refactored return type from standard BTreeSet to custom PciTree struct - Removed special FullPciIoAddress type, since segment number is PciRoot dependent - During enumeration, skip branches we have already seen - During enumeration, collect tree topology information (which child bus linked from where) - Add complicated pci structure in integration test vm - Print child busses for every device entry in integration test
602c776 to
a82b06c
Compare
phip1611
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're almost there! Just a few nits
| } | ||
| } | ||
|
|
||
| pub(crate) fn push_bus(&self, bus: u8) -> bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Further, should this be called can_bush_bridge to be consistent with the other method`
| pub(crate) fn push_bus(&self, bus: u8) -> bool { | |
| pub(crate) fn can_push_bus(&self, bus: u8) -> bool { |
| pub fn iter_subsequent_busses_for(&self, addr: PciIoAddress) -> impl Iterator<Item = u8> { | ||
| self.bus_anchors | ||
| .iter() | ||
| .filter(move |&(_, parent)| *parent == addr) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you really need move here? PciIoAddress is Copy
|
|
||
| /// Iterate over all subsequent busses below the given `addr`. | ||
| /// This yields 0 results if `addr` doesn't point to a PCI bridge. | ||
| pub fn iter_subsequent_busses_for(&self, addr: PciIoAddress) -> impl Iterator<Item = u8> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bz convention I think all functions returning an iterator end with iter
| pub fn iter_subsequent_busses_for(&self, addr: PciIoAddress) -> impl Iterator<Item = u8> { | |
| pub fn subsequent_busses_filtered_iter(&self, addr: PciIoAddress) -> impl Iterator<Item = u8> { |
| self.devices.insert(addr); | ||
| } | ||
|
|
||
| pub(crate) fn push_bridge(&mut self, addr: PciIoAddress, child_bus: u8) -> bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| pub(crate) fn push_bridge(&mut self, addr: PciIoAddress, child_bus: u8) -> bool { | |
| /// Pushes a new bridge into the topology. | |
| /// | |
| /// Returns `false` if the bus is already in the topology and `true` | |
| /// if the bridge was added to the topology. | |
| pub(crate) fn push_bridge(&mut self, addr: PciIoAddress, child_bus: u8) -> bool { |
|
|
||
| /// Get the segment number of this PCI tree. | ||
| #[must_use] | ||
| pub const fn segment_nr(&self) -> u32 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| pub const fn segment_nr(&self) -> u32 { | |
| pub const fn segment(&self) -> u32 { |
| // +-1f.2 | ||
| // \-1f.3 | ||
| // In the diagram, `0000:03:00.0` and `0000:04:00.0` are just dummy SCSI devices | ||
| // connected below the PCIe switch, to correct recursion in the bus enumeration implementation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sentence sounds broken? Maybe this
| // connected below the PCIe switch, to correct recursion in the bus enumeration implementation. | |
| // connected below the PCIe switch, to test correct recursion in the bus enumeration implementation. |

BTreeSet<PciIoAddress>to customPciTreestruct with tree topology informationPreviously, we iterated over the bus range from the ACPI descriptor. I changed this in my last MR to only visit the first in the range. I changed this back to iterate over all of the entries, but skip the ones we have seen previously - now that that's easily possible. I decided that better safe than sorry is the best way. The iteration over all child busses already saved our ass once - let's not willingly take this safety net away. Sorry for the back and forth here.
The plan for device paths is now to add something like:
PciTree::device_path(&self, addr: PciIoAddress) -> PoolDevicePath.Checklist